package mornd.test2;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.aop.Pointcut;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DefaultPointcutAdvisor;

/**
 * @author: mornd
 * @dateTime: 2023/5/6 - 16:28
 * 自定义 aspectj 切面实现
 */
public class Demo1 {
    public static void main(String[] args) {
        // 配置切点 springframework.aop 包下的 PointCut 接口实现类
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        // 设置切点表达式
        pointcut.setExpression("execution(* foo())");
        // 配置通知(最基本也是最重要的通知，其他通知底层最终都会转换成此通知执行)
        MethodInterceptor advice = new MethodInterceptor() {
            @Override
            public Object invoke(MethodInvocation invocation) throws Throwable {
                System.out.println("before...");
                Object r = invocation.proceed(); // 调用目标方法
                System.out.println("after...");
                return r;
            }
        };

        // 配置切面
        DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut, advice);

        /**
         * spring 何时使用 jdk，何时使用 cglib？
         *      由 org.springframework.aop.framework.ProxyConfig#proxyTargetClass 属性决定
         * 3中情况：
         * proxyTargetClass = false：检测目标是否实现接口，如果有，使用 jdk
         * proxyTargetClass = false：检测目标是否实现接口，如果没有，使用 cglib
         * proxyTargetClass = true：不管有没有实现接口，强制使用 cglib
         */
        // 创建代理
        I1 t1 = new Target1();
        ProxyFactory factory = new ProxyFactory();
        factory.setTarget(t1);
        factory.addAdvisor(advisor);
        /**
         * 如果不主动设置，spring 不知道目标是否实现了接口，如果不设置，就算目标实现了接口，还是会使用 cglib
         */
        factory.setInterfaces(t1.getClass().getInterfaces());
        // true表示强制设置为 cglib 代理
        //factory.setProxyTargetClass(true);
        // 创建代理对象
        I1 proxy = (I1) factory.getProxy();
        System.out.println("代理对象：" + proxy.getClass());
        // 执行代理对象方法
        proxy.foo();
        proxy.bar();
    }

    interface I1 {
        void foo();

        void bar();
    }

    static class Target1 implements I1 {
        @Override
        public void foo() {
            System.out.println("target1 foo");
        }

        @Override
        public void bar() {
            System.out.println("target1 bar");
        }
    }

    static class Target2 implements I1 {
        @Override
        public void foo() {
            System.out.println("target2 foo");
        }

        @Override
        public void bar() {
            System.out.println("target2 bar");
        }
    }
}
